from abc import ABC, abstractmethod
import math


# 1. 抽象基类（接口）：定义图形的基本行为
class Shape(ABC):
    """几何图形的抽象基类，定义面积和周长的计算接口"""
    
    @abstractmethod
    def area(self):
        """计算图形面积（抽象方法，子类必须实现）"""
        pass
    
    @abstractmethod
    def perimeter(self):
        """计算图形周长（抽象方法，子类必须实现）"""
        pass
    
    def __str__(self):
        """返回图形的字符串描述（可被子类重写）"""
        return f"{self.__class__.__name__} - 面积: {self.area():.2f}, 周长: {self.perimeter():.2f}"


# 2. 具体图形类：继承自Shape并实现抽象方法
class Circle(Shape):
    """圆形类"""
    
    def __init__(self, radius):
        """
        构造函数：初始化圆形
        Args:
            radius: 半径（必须为正数）
        """
        if radius <= 0:
            raise ValueError("圆的半径必须为正数")
        self.radius = radius  # 实例属性
    
    def area(self):
        """计算圆的面积：πr²"""
        return math.pi * self.radius ** 2
    
    def perimeter(self):
        """计算圆的周长：2πr"""
        return 2 * math.pi * self.radius


class Rectangle(Shape):
    """矩形类"""
    
    def __init__(self, length, width):
        """
        构造函数：初始化矩形
        Args:
            length: 长度（必须为正数）
            width: 宽度（必须为正数）
        """
        if length <= 0 or width <= 0:
            raise ValueError("矩形的长和宽必须为正数")
        self.length = length
        self.width = width
    
    def area(self):
        """计算矩形面积：长×宽"""
        return self.length * self.width
    
    def perimeter(self):
        """计算矩形周长：2×(长+宽)"""
        return 2 * (self.length + self.width)
    
    # 重写父类的__str__方法，增加特有信息
    def __str__(self):
        return f"Rectangle(长: {self.length}, 宽: {self.width}) - 面积: {self.area():.2f}, 周长: {self.perimeter():.2f}"


class Triangle(Shape):
    """三角形类"""
    
    def __init__(self, a, b, c):
        """
        构造函数：初始化三角形（需满足三角形不等式）
        Args:
            a, b, c: 三条边的长度（必须为正数，且任意两边之和大于第三边）
        """
        if a <= 0 or b <= 0 or c <= 0:
            raise ValueError("三角形的边长必须为正数")
        if (a + b <= c) or (a + c <= b) or (b + c <= a):
            raise ValueError("三角形任意两边之和必须大于第三边")
        self.a = a
        self.b = b
        self.c = c
    
    def area(self):
        """计算三角形面积：使用海伦公式"""
        s = (self.a + self.b + self.c) / 2  # 半周长
        return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))
    
    def perimeter(self):
        """计算三角形周长：三边之和"""
        return self.a + self.b + self.c


# 3. 图形管理类：管理多个图形对象
class ShapeManager:
    """图形管理器，用于批量管理和计算图形"""
    
    def __init__(self):
        """构造函数：初始化图形列表"""
        self.shapes = []  # 存储图形对象的列表
    
    def add_shape(self, shape):
        """
        添加图形到管理器
        Args:
            shape: 继承自Shape的实例
        """
        if not isinstance(shape, Shape):
            raise TypeError("只能添加Shape类或其子类的实例")
        self.shapes.append(shape)
    
    def total_area(self):
        """计算所有图形的总面积"""
        return sum(shape.area() for shape in self.shapes)
    
    def total_perimeter(self):
        """计算所有图形的总周长"""
        return sum(shape.perimeter() for shape in self.shapes)
    
    def print_all_shapes(self):
        """打印所有图形的信息"""
        if not self.shapes:
            print("没有图形可显示")
            return
        print("所有图形信息：")
        for i, shape in enumerate(self.shapes, 1):
            print(f"[{i}] {shape}")


# 测试代码
if __name__ == "__main__":
    try:
        # 创建图形实例
        circle = Circle(radius=5)
        rectangle = Rectangle(length=4, width=6)
        triangle = Triangle(a=3, b=4, c=5)  # 直角三角形
        
        # 创建图形管理器并添加图形
        manager = ShapeManager()
        manager.add_shape(circle)
        manager.add_shape(rectangle)
        manager.add_shape(triangle)
        
        # 打印所有图形信息
        manager.print_all_shapes()
        
        # 计算总面积和总周长
        print(f"\n所有图形总面积：{manager.total_area():.2f}")
        print(f"所有图形总周长：{manager.total_perimeter():.2f}")
        
        # 测试错误情况（无效的图形参数）
        try:
            invalid_circle = Circle(radius=-2)  # 半径为负数
        except ValueError as e:
            print(f"\n错误提示：{e}")
        
        try:
            invalid_triangle = Triangle(a=1, b=1, c=3)  # 不满足三角形不等式
        except ValueError as e:
            print(f"错误提示：{e}")
            
    except Exception as e:
        print(f"发生错误：{e}")